﻿using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Logging.Console;
using Microsoft.Extensions.Options;

namespace RuoYi.Framework.Logging;

/// <summary>
///   控制台默认格式化程序拓展
/// </summary>
[SuppressSniffer]
public sealed class ConsoleFormatterExtend : ConsoleFormatter, IDisposable
{
  /// <summary>
  ///   日志格式化选项刷新 Token
  /// </summary>
  private readonly IDisposable _formatOptionsReloadToken;

  /// <summary>
  ///   是否启用控制台颜色
  /// </summary>
  private bool _disableColors;

  /// <summary>
  ///   日志格式化配置选项
  /// </summary>
  private ConsoleFormatterExtendOptions _formatterOptions;

  /// <summary>
  ///   构造函数
  /// </summary>
  /// <param name="formatterOptions"></param>
  public ConsoleFormatterExtend(IOptionsMonitor<ConsoleFormatterExtendOptions> formatterOptions)
    : base("console-format")
  {
    (_formatOptionsReloadToken, _formatterOptions) =
      (formatterOptions.OnChange(ReloadFormatterOptions), formatterOptions.CurrentValue);
    _disableColors = _formatterOptions.ColorBehavior == LoggerColorBehavior.Disabled ||
                     (_formatterOptions.ColorBehavior == LoggerColorBehavior.Default && Console.IsOutputRedirected);
  }

  /// <summary>
  ///   释放非托管资源
  /// </summary>
  public void Dispose()
  {
    _formatOptionsReloadToken?.Dispose();
  }

  /// <summary>
  ///   写入日志
  /// </summary>
  /// <typeparam name="TState"></typeparam>
  /// <param name="logEntry"></param>
  /// <param name="scopeProvider"></param>
  /// <param name="textWriter"></param>
  public override void Write<TState>(in LogEntry<TState> logEntry, IExternalScopeProvider? scopeProvider, TextWriter textWriter)
  {
    // 获取格式化后的消息
    var message = logEntry.Formatter?.Invoke(logEntry.State, logEntry.Exception);

    // 创建日志消息
    var logDateTime = _formatterOptions.UseUtcTimestamp ? DateTime.UtcNow : DateTime.Now;
    var logMsg = new LogMessage(logEntry.Category, logEntry.LogLevel, logEntry.EventId, message, logEntry.Exception, null,
      logEntry.State, logDateTime, Environment.CurrentManagedThreadId, _formatterOptions.UseUtcTimestamp, App.GetTraceId());

    string standardMessage;

    // 是否自定义了自定义日志格式化程序，如果是则使用
    if (_formatterOptions?.MessageFormat != null)
    {
      // 设置日志上下文
      logMsg = Penetrates.SetLogContext(scopeProvider, logMsg, _formatterOptions.IncludeScopes);

      // 设置日志消息模板
      standardMessage = _formatterOptions.MessageFormat(logMsg);
    }
    else
    {
      // 获取标准化日志消息
      standardMessage = Penetrates.OutputStandardMessage(logMsg
        , _formatterOptions.DateFormat
        , true
        , _disableColors
        , _formatterOptions.WithTraceId
        , _formatterOptions.WithStackFrame);
    }

    // 判断是否自定义了日志筛选器，如果是则检查是否符合条件
    if (_formatterOptions.WriteFilter?.Invoke(logMsg) == false) return;

    // 空检查
    if (message is null) return;

    // 判断是否自定义了日志格式化程序
    if (_formatterOptions.WriteHandler != null)
      _formatterOptions.WriteHandler?.Invoke(logMsg, scopeProvider, textWriter, standardMessage, _formatterOptions);
    else
      // 写入控制台
      textWriter.WriteLine(standardMessage);
  }

  /// <summary>
  ///   刷新日志格式化选项
  /// </summary>
  /// <param name="options"></param>
  private void ReloadFormatterOptions(ConsoleFormatterExtendOptions options)
  {
    _formatterOptions = options;
    _disableColors = options.ColorBehavior == LoggerColorBehavior.Disabled ||
                     (options.ColorBehavior == LoggerColorBehavior.Default && Console.IsOutputRedirected);
  }
}
